perm filename TCPMSC.MAC[IP,SYS] blob
sn#680223 filedate 1982-10-14 generic text, type T, neo UTF8
;CWL:<403-TCP>TCPMSC.MAC.40303 26-Apr-82 17:14:48, Edit by CLYNN
; Max segment option subbort, IP information support
;<403-TCP>TCPMSC.MAC.40301 29-Jan-82 15:04:02, Edit by CLYNN
; Updated for TCP release 3
; Combined pre-FILHDR code & FILHDR into TCPIPK
; MAXTCB becomes TCBMAX in STG, TRACEP becomes INTTRC
;[BBNF]<401-TCP>TCPMSC.MAC.128, 27-Jul-81 12:48:00, Ed: CLYNN
; Fix: Matching TCB check at CHKAD9, No memory return in TCBINI,
; No space for new TCB in NEWTCB
;<MNET-TCP>TCPMSC.MAC.3, 4-Apr-81 17:22:39, Edit by TAPPAN
; Add multinet stuff under a conditional
SEARCH INPAR,TCPPAR,PROLOG
IFN MNET,<SEARCH MNTPAR>
TTITLE TCPMSC
SUBTTL TCP Miscellaneous routines. William W. Plummer, 14Jan77
SWAPCD
COMMENT !
* CHKWND ... 3 ...... Check if a sequence number is within a window
* OVRLAP ... 4 ...... Check if two segments overlap
* ONLCLT ... 5 ...... Check if source of packet is using our clock
* GETISN ... 5 ...... Get current value of Initial Sequence Number
* PKTEND ... 6 ...... Returns sequence number of end of packet plus one
* NULPKT ... 6 ...... Test a packet for containing something to be ACKd
* TRMPKT ... 7 ...... Trim storage required by a packet
* CLRBLK ... 8 ...... Clear a block before stuffing it
* LCKCAL ... 9 ...... Lock a lock and call a funtion
* CHKADD ... 10 ...... Lookup a connection and maybe create new one
* TCBINI ... 14 ...... Initialize the TCB Hash Table
NEWTCB ... 15 ...... Initialize a new connection block
* TCPMXP ... 17 ...... Update maximum packet size generated (TSMXP)
* TCPIPK ... 18 ...... Build packet & fill in common header information
!
; CheckWindow(Left, Sequence, Right)
; Test "Sequence" to see if it is between "Left" (inclusive) and "Right"
; (not incl.). Sequence numbers are modulo MAXSEQ and are always
; positive when represented in a 36-bit word.
;T1/ Left
;T2/ Sequence
;T3/ Right
;
; CALL CHKWND
;Ret+1: always. T1 has -1 if Sequence is in the window, 0 if not
CHKWND::TEMP <VAL,SEQ,RIGHT,LEFT>
MOVEM T1,LEFT ; Make T1 available for value
SETZ VAL, ; Init value
CAMG LEFT,RIGHT ; Crosses 0?
SOSA VAL ; No. Get a -1 to return
EXCH LEFT,RIGHT ; Yes. Reverse Left and Right.
CAMGE SEQ,RIGHT
CAMGE SEQ,LEFT
SETCA VAL, ; Out of window. Complement initial guess
RESTORE
RET
; Test to see if two sequence number segments have one or more common
; points. The two segments are semi-open on the right, similar
; to CHKWND.
;T1/ Left1
;T2/ Right1
;T3/ Left2
;T4/ Right2
;
; CALL OVRLAP
;Ret+1 always, T1 is -1 if overlap exists, 0 if not
OVRLAP::LOCAL <LEFT1,LEFT2,RIGHT2>
MOVEM T1,LEFT1
DMOVEM T3,LEFT2 ; T3,T4 to LEFT2,RIGHT2
EXCH T2,T3
CALL CHKWND
JUMPN T1,OVRLAX
MOVE T1,LEFT2
MOVE T2,LEFT1
MOVE T3,RIGHT2
CALL CHKWND
OVRLAX: RESTORE
RET
; Test to see if the current packet was sent by a host which
; is using the same timebase as this host. So that we will know
; if the time stamp is valid
;PKT/ (Extended) Pointer to the packet under consideration
;
; CALL ONLCLT
;Ret+1: always, T1 non-0 if packet has a useable timestamp
ONLCLT::LOAD T1,PISH,(PKT) ; Get the 32-bit source address
IFN MNET,< ; If multiple address'
CALL LCLHST ; Is it me?
SETZ T1, ; No, clear T1
>
IFE MNET,<
CAME T1,INETID ; Is it me?
TDZA T1,T1 ; No, clear it
SETO T1, ; Else -1
>
RET
; Get the current value of the Initial Sequence Number curve. This
; curve is a straight line which starts at 0 and goes through the
; maximum sequence number minus 1 every cycle time of the network.
; It steps once a second.
; CALL GETISN
;Ret+1: always, ISN in T1
GETISN::
IFKA < GTAD ; Day,,Sec
HRRZS T1 ; Save second number within day
DIVI T1,↑D<24*60*60> ; Get binary fraction of day
>
IFNKA < CALL LGTAD ; Day,,tick
HRRZS T1 ; Save tick with day
LSH T1,↑D17 ; Make into binary fraction of day
>
; TCPISN is [↑D<<MAXSEQ/8>*<<24*60*60>/CYCTIM>>]
MUL T1,TCPISN ; Get sequence number
LSH T1,@TCPISN+1 ; Scale factor of 8 above
MODSEQ T1
RET
; PKTEND(PKT) returns the sequence number following the packet
;PKT/ (Extended) Packet pointer
;TPKT/ (Extended) pointer to TCP part of packet
;
; CALL PKTEND
;Ret+1: always. End of packet plus one in T1
PKTEND::LOAD T1,PSEQ,(TPKT) ; Get the start of the packet
LOAD T2,PCTL,(TPKT) ; Get word containing control flags
TXNE T2,<PSYN> ; Count one for SYN
ADDI T1,1
TXNE T2,<PFIN> ; Another if FIN
ADDI T1,1
LOAD T2,PIPL,(PKT) ; Length of whole packet in bytes
LOAD T3,PIDO,(PKT) ; Number of words in Internet part
LOAD T4,PTDO,(TPKT) ; Number of words in TCP header
ADD T3,T4 ; Total header word count
ASH T3,2 ; Byte count
SUB T2,T3 ; Difference is # bytes in data part
ADD T1,T2 ; Each data byte is one sequence slot
MODSEQ T1 ; Take MOD field size
RET
; NULPKT(PKT) Tells if packet doesn't contain anything ACK-able
; (SYN, data, FIN)
;PKT/ (Extended) Packet pointer
;TPKT/ (Extended) pointer to TCP part of packet
;
; CALL NULPKT
;Ret+1: Always. T1 -1 if packet is null, 0 if something
NULPKT::SETZ T1, ; Assume something ackable
LOAD T2,PIPL,(PKT) ; Total packet length
LOAD T3,PIDO,(PKT) ; Offset to Internet data in words
LOAD T4,PTDO,(TPKT) ; Offset to TCP data in words
ADD T3,T4 ; Number of header words, total
ASH T3,2 ; Number of header bytes, total
CAMLE T2,T3 ; Anything in TCP data part?
JRST NULPKX ; Yes. Packet is not null
LOAD T2,PCTL,(TPKT) ; Get word of control flags
TXNN T2,<PSYN!PFIN>
SETO T1, ; No data, no control. Pkt is null.
NULPKX: RET
; TRMPKT(PKT) Return excess storage not used in packet block
;PKT/ (Extended) Packet pointer
;TPKT/ (Extended) pointer to TCP part of packet
;
; CALL TRMPKT
;Ret+1: Always. PKT may come back 0 if storage unavailable.
; Copy the little piece into a new block.
; Return all of the whole (big) packet.
TRMPKT::JE PFSIZ,(PKT),TRMPKX ; Only full-size packets can be trimmed
MOVE T1,INTNFI ; Number of free input buffer right now
CAML T1,INTNIB ; Number desired
EXIT TRMPKX ; No reason to trim. Space not tight.
LOAD T1,PIPL,(PKT) ; Internet Packet Length in bytes
ADDI T1,<4*PKTELI>+3 ; Total length, set to round up
ASH T1,-1 ; Twice number of words in packet
CAML T1,INTXPW ; Too big. Wont leave a useful tail.
EXIT TRMPKX ; or lengths smashed on input packet?
ASH T1,-1 ; # words in packet
PUSH P,T1 ; Save the new size
MOVX T1,PT%TTP ; Going to trim packet
TDNE T1,INTTRC ; Want trace?
CALL PRNPKT ; Yes
MOVE T1,(P) ; New size, w
CALL GETBLK ; And get a new little chunk
POP P,T2 ; Get back size
JUMPE T1,[MOVX T1,PT%TKT ; Killed because no space
TDNE T1,INTTRC ; Want trace?
CALL PRNPKT ; Yes
JRST TRMPK9] ; Don't copy into non-X packet
PUSH P,T1 ; Save for later
XMOVEI T3,PKTSII(T1) ; Destination
MOVEI T1,-PKTSII(T2) ; Number of words to copy
XMOVEI T2,PKTSII(PKT) ; Source
CALL XBLTA ; Do a BLT
POP P,T1 ; Restore destination pkt ptr
SETZM PKTQ(T1) ; Indicate not queued
SETZRO PFLGS,(T1) ; Clear all internal flags
TRMPK9:
PUSH P,T1 ; Save pointer to the new packet (or 0)
MOVE T2,TPKT ; Parallel pointer to TCP portion
SUB T2,PKT ; Compute offset
PUSH P,T2 ; Save it
CALL RETPKT ; Return be big piece
POP P,TPKT ; Get back offset
POP P,PKT ; Here's the replacement (or 0)
ADD TPKT,PKT ; Reconstruct pointer
TRMPKX: RET
; CLRBLK Clear a block to be sure unstuffed fields are 0
;T1/ (Extended) pointer to block
;T2/ Size of block
;
; CALL CLRBLK
;Ret+1: Always.
CLRBLK::EXCH T1,T2 ; Size to T1, Source to T2
SUBI T1,1 ; Number of transfers is 1 less
XMOVEI T3,1(T2) ; Destination
SETZM 0(T2) ; Clear a word.
CALLRET XBLTA ; Clear the rest
; LCKCAL(Lock, Fn, Arg1, Arg2)
; Call Fn(Arg1, Arg2) with Lock set & NOINT
;T1/ (Extended) Lock pointer
;T2/ (Extended) Function address
;T3/ Arg1
;T4/ Arg2
;
; CALL LCKCAL
;Ret+1: always. T1 has value of Fn(Arg1, Arg2)
; Can be used for cross-section calls
LCKCAL::PUSH P,T1 ; (Ext) Lock address (save for UNLCK)
PUSH P,T2 ; (Ext) Function to CALL
PUSH P,T3 ; Save args from SETLCK
PUSH P,T4
MOVE T1,-3(P) ; Get pointer to the lock
CALL SETLCK ; Test and set the lock (may wait)
POP P,T2 ; Put args in standard place for a call
POP P,T1
CALL @0(P) ; Call function
;LCKCA3:
SUB P,BHC+1 ; Drop Function address
EXCH T1,0(P) ; Save the value while we unlock...
CALL UNLCK
POP P,T1
RET
; CHKADD Lookup up a connection and maybe create a new one
; If the desired (possibly wild) connection is found, the argument
; function is called with the TCB locked. If no TCB is found,
; the value of CHKADD is -1,,errorcode. Otherwise the value is
; that of the function called, which may also be an error value.
; T1/ (Extended) Pointer to argument block defined by CHKADL
; NOINT
; CALL CHKADD
;Ret+1: always. Value in T1, TCB set up. ELP+↑D13. Illegal port (LP=0)
; (net) ELP+↑D5. Pkt w/ wild FH/FP; EFP+↑D7. No TCB matches
; (JSYS) ELT+↑D4. No storage, wait bit, too many connections
CHKADD::STACKL <WILD1>
CHKADL (<TCBX,TCB.FH,TCB.FP>) ; PARAMS & other LOCALs
MOVEM T1,PARAMS ; Save pointer to parameters
HRROI T1,ELP+↑D13 ; "Illegal port"
SKIPN LP
EXIT CHKADX ; Should never have to lookup wild LP
HRROI T1,ELP+↑D5
SKIPE FP ; Wild FP and/or FH ok only if "listen"
SKIPN FH
SKIPE JCN ; Called from a JSYS?
CAIA
EXIT CHKADX ; Bad packet from network (FP=0 or FH=0)
; Get unique access to the TCB Hash table. This means having it locked
; with the TCBH Use Count = 0.
CHKAD1: XMOVEI T1,TCBHLK ; Pointer to the TCBH Lock
CALL SETLCK ; Test and set the lock
SKIPG TCBHUC ; TCBH Use Count. Any readers?
JRST CHKAD3 ; OK. We have sole access.
XMOVEI T1,TCBHLK ; Pointer to the lock
CALL UNLCK ; Unlock it.
MOVEI T1,TCBHUC ; Pointer to the use count
CALL DISE ; Wait for it to go to zero
JRST CHKAD1 ; and try again.
CHKAD3:
; Get hash index to the TCB Hash table
MOVE T1,LP ; Local port is what is hashed on
LSH T1,-3
ADDI T1,↑D23 ; Hash LP into a TCBH index
IMUL T1,LP
IDIVI T1,TCBHSZ ; Size of the hash table
ADD T2,TCBH ; (Ext) Location within TCBH
MOVEM T2,TCBX ; Save the (ext) pointer to q head
; Scan the TCB queue which has its head in the slot at TCBX
MOVE TCB,TCBX ; Initize the scan pointer
SETZM WILD1 ; No Wild match found yet
CHKAD4: LOAD TCB,QNEXT,(TCB) ; Get next (first) thing on queue
SETSEC TCB,INTSEC ; Make extended address
CAMN TCB,TCBX ; Points back to head?
JRST CHKAD6 ; Yes. Scan done.
LOAD T1,TOWNR,(TCB) ; Get Job number which owns this tcb
SKIPE JCN ; Any job ok if called from net side
CAMN T1,JOBNO ; Must stay in this job
CAIA ; OK to think about this TCB
JRST CHKAD4 ; Skip it and try next
LOAD T1,TLP,(TCB) ; Get the Local Port from this TCB
CAME T1,LP ; Does it match what we are looking for?
JRST CHKAD4 ; No. Try next TCB
LOAD TCB.FH,TFH,(TCB) ; Get foreign host
LOAD TCB.FP,TFP,(TCB) ; and foreign port
CAMN TCB.FH,FH ; Compare these with what
CAME TCB.FP,FP ; is being sought
JRST CHKAD5 ; Not an exact match. Maybe OK for wild
LOAD T4,TLH,(TCB) ; Check local address also
CAME T4,LH
JFCL ; JRST CHKAD5 ; Not an exact match. Maybe OK for wild
; TCB points to an exact match. If CHKADD was called from the JSYS
; side, it means the user is trying to say more about the connection.
SKIPE JCN ; Called from a JSYS?
JRST CHKAD6 ; Yes. Go use this exact match.
LOAD T1,TRSYN,(TCB) ; Get state of Receive synchronization
LOAD T2,TSSYN,(TCB) ; and state of Send synch.
CAIN T1,NOTSYN ; Recv side still open?
CAIE T2,NOTSYN ; Send side still open?
JRST CHKAD6 ; Yes. Reuse this TCB.
JRST CHKAD4 ; Both closed. Pkt cannot reactivate
; conn. Look for another incarnation.
; See if this TCB should be remembered for use as a wild one.
CHKAD5: SKIPN WILD1 ; Continue scan if already have a wild match
SKIPN WILDOK ; Caller says OK to use wild TCB?
JRST CHKAD4 ; No. Keep looking for exact match.
JUMPE TCB.FH,.+3 ;*** ; TCB has wild foreign host
CAME TCB.FH,FH ;*** ; or exact match means ok.
JRST CHKAD4 ;*** ; No. Resume scan.
JUMPE TCB.FP,.+3 ;*** ; Wild foreign port in TCB?
CAME TCB.FP,FP ;*** ; or exact match?
JRST CHKAD4 ;*** ; No good.
MOVEM TCB,WILD1 ;*** ; Save the location of the wild TCB
JRST CHKAD4 ; Continue looking for exact match.
; End of scan. TCB has the TCB to use or points at queue head (TCBX)
; if none found. WILD1 is 0 or pointer to a wild TCB.
CHKAD6: CAME TCB,TCBX ; Found an exact match?
JRST CHKAD9 ; Yes. Go use TCB
SKIPN WILD1 ; Have a wild match?
JRST CHKAD7 ; No.
; Bind a wild match.
MOVE T1,FH ; Get the desired foreign host
MOVE T2,FP ; and foreign port
MOVE T3,LH ; and local host
MOVE TCB,WILD1 ; This is the TCB to work with
STOR T1,TFH,(TCB) ; Store in the wild TCB
STOR T2,TFP,(TCB)
STOR T3,TLH,(TCB)
JRST CHKAD9 ; Do it.
; No wild match and no exact match. If called from JSYS Create the connection.
; NOTE TCB=TCBX & WILD1=0
CHKAD7: CAMN TCB,TCBX ; If have a TCB go to CHKAD9
SKIPN JCN ; Called from a JSYS?
JRST CHKAD9 ; Net. Don't create a TCB
; JSYS & no TCB
MOVE T1,PARAMS ; Argument block address
MOVE T2,TCBX ; (Ext) Where to enqueue the new TCB
CALL NEWTCB ; Create it and initialize it.
JUMPN TCB,CHKAD9 ; Go use the new TCB
MOVEI T1,TCBHLK ; Ran out of free storage.
CALL UNLCK ; Unlock TCBH
HRROI T1,ELT+↑D4 ; "No room for another connection"
EXIT CHKADX ; Report the error to the caller
; TCB has the TCB to use or is equal to TCBX if not.
CHKAD9: JRST CHKA10 ; Following doesn't work, why??
CAME TCB,TCBX ; Found a TCB?
SKIPN JCN ; And called from the JSYS side?
JRST CHKA10 ; No.
LOAD T1,TJCN,(TCB) ; Get original JCN of TCB
JUMPE T1,CHKA10 ; None. Use the new one.
EXCH T1,JCN ; Use the original JCN
CAME T1,JCN ; If temporary one is different,
CALL RETJCN ; Return it (RH of JCNTCB is 0)
; If a TCB was found/created, lock it and call the argument function.
CHKA10: AOS TCBHUC ; Indicate TCBH has a reader
MOVEI T1,TCBHLK ; Pointer to the TCBH lock
CALL UNLCK ; Unlock TCBH with use count gt 0
HRROI T1,EFP+↑D7 ; "No such TCB"
CAMN TCB,TCBX ; Did we locate a TCB?
JRST CHKA11 ; No. Report the error
XMOVEI T1,TCBLCK(TCB) ; Pointer to the TCB Lock
MOVE T2,FN ; Function to be called
MOVE T3,JCN ; Argument for the function
MOVE T4,ARG1 ; The argument passed through
CALL LCKCAL ; Lock the lock and call the function
CHKA11: SOS TCBHUC ; Indicate TCBH may change now
CHKADX: CHKADR ; Restore
RET
; TCBINI Initialize the TCB Hash Table
; CALL TCBINI
;Ret+1: Always
TCBINI::LOCAL <TCBX>
MOVEI T1,TCBHSZ*QSZ ; Size of the TCB Hash table
CALL GETBLK ; Qs must point to things in same section!
JUMPE T1,TCBINX ; No space
MOVEM T1,TCBH ; (Ext) Loc of hash table.
IF1 <IFN QSZ-1,<PRINTX ? QSZ isn't 1, Fix code>>
MOVSI TCBX,-TCBHSZ ; Set to scan TCBH (assumes QSZ==1)
TCBIN1: HRRZ T1,TCBX ; Index within TCBH table
ADD T1,TCBH ; Pointer to table base
CALL INITQ ; Initialize as a queue
AOBJN TCBX,TCBIN1 ; Loop over all slots
SETZM TCBHUC ; Clear the use count
XMOVEI T1,TCBHLK ; Pointer to the lock on TCBH
CALL CLRLCK ; Initialize it
TCBINX: RESTORE
RET
; NEWTCB(LP, FH, FP, TCBX) Initialize a new connection block
;T1/ PARAMS ; (Ext) address of parameter block
;T2/ TCBX ; (Ext) Adr of TCB Hash table entry
;
; CALL NEWTCB
;Ret+1: always. TCB points to the TCB or is 0 if no space,
; too many conn, no wait bits
NEWTCB: CHKADL (TCBX)
MOVEM T1,PARAMS ; Argument block address
MOVEM T2,TCBX ; Where to enqueue new TCB
MOVE T2,TCBCNT ; Current number of connections
CAML T2,TCBMAX ; Test against max we support at once
JRST NEWTCE ; No room for another.
MOVX T1,TCBSIZ ; Size of a connection block
CALL GETBLK ; Get a block of free storage
JUMPE T1,NEWTCE ; None available. Fail.
MOVEM T1,TCB ; Put (ext) adr in standard place
MOVX T2,TCBSIZ ; Size again for CLRBLK
CALL CLRBLK
MOVE T1,LH ; Set the local host
STOR T1,TLH,(TCB)
STOR T1,TOPLH,(TCB)
MOVE T2,LP ; Set the local port
STOR T2,TLP,(TCB)
MOVE T3,FH ; Set the foreign host
STOR T3,TFH,(TCB)
STOR T3,TOPFH,(TCB)
MOVE T4,FP ; Set the foreign port
STOR T4,TFP,(TCB)
STOR T4,TOPFP,(TCB)
JUMPN T4,NEWTC0 ; Wild foreign port?
SETONE TWLDP,(TCB) ; Yes.
NEWTC0:
EXCH 0,T3
LOAD T4,NETCLS ; Get network class bit(s)
EXCH 0,T3
TDZ T3,INTCLS(T4) ; Drop class bit(s)
TDZE T3,INTNET(T4) ; Net field zero?
JRST NEWTC1 ; No, but host might be.
JUMPN T3,NEWTC2 ; Yes, but host isn't, neither wild
SETONE <TWLDN,TWLDT>,(TCB) ; Wild net & host
JRST NEWTC2
NEWTC1: JUMPN T3,NEWTC2 ; Wild foreign host?
SETONE TWLDT,(TCB) ; Yes. Wild host, net specified
NEWTC2:
XMOVEI T1,TCBSBQ(TCB) ; TCB Send buffer queue
CALL INITQ ; Initialize it.
XMOVEI T1,TCBRXQ(TCB) ; TCB Retransmission queue
CALL INITQ ; Initialize it.
XMOVEI T1,TCBRBQ(TCB) ; TCB Receive buffer queue
CALL INITQ ; Initialize it.
XMOVEI T1,TCBRPQ(TCB) ; TCB Receive packet queue
CALL INITQ ; Initialize it.
CALL ASNWTB ; Assign a wait bit index for open/close
JUMPL T1,NEWTC9 ; Jump if we didn't get the bit.
STOR T1,TOPNF,(TCB) ; Set into TCB
CALL CLRWTB ; Initialize to zero state (closed)
CALL ASNWTB ; Get another bit for error events
JUMPL T1,NEWTC8 ; Jump if that failed
STOR T1,TERRF,(TCB) ; Set into TCB
CALL CLRWTB ; Clear it. (No error yet)
XMOVEI T1,TCBLCK(TCB) ; Pointer to the TCB lock
CALL CLRLCK ; Clear it.
MOVX T1,↑D60 ; Default time to live
STOR T1,TTTL,(TCB) ; for this connection
MOVX T1,<<1B<35-WID(PIPL)>>-1> ; Max possible packet 2**16-1 octets
STOR T1,TSMXP,(TCB) ; including headers
XMOVEI T1,TCBQ(TCB) ; (Ext) Pointer to the TCB just initialized
MOVE T2,TCBX ; (Ext) Adr of TCB Hash table entry (of Q's)
CALL NQ ; Place it on the right queue
AOS TCBCNT ; Count as another connection
EXIT NEWTCX
NEWTC8: LOAD T1,TOPNF,(TCB) ; Oh well. Have to back out.
CALL RELWTB ; Release the open/close wait bit
NEWTC9: MOVE T1,TCB ; Pointer to the connection block
CALL RETBLK ; Give back that storage
NEWTCE: SETZ TCB, ; Tell caller the bad news.
NEWTCX: CHKADR
RET
; TSMXP = TCPMXP (TCB) Update maximum packet size generated on connection
; T1/ Foreign specified limit (from option), or 0
; CALL TCPMXP
TCPMXP::
IFN MNET,<SAVP1>
LOCAL <PSZ>
SKIPLE PSZ,T1 ; Save argument if specified
JRST TCPMX6 ; Try to use it
LOAD T1,TFH,(TCB) ; Get foreign address
IFN MNET,<CALL LCLHST> ; Is it one of us?
IFE MNET,<CAME T1,INETID> ; Is it to me?
SKIPA PSZ,[↑D576] ; No, sociable maximum
MOVE PSZ,TCPBYS ; Yes, big ones
; Packet Radio Kludge - small packets to certain nets
LOAD T2,TFH,(TCB) ; Foreign address contains
NETNUM T2,T2 ; Foreign net number
CAIE T2,↑D1 ; BBN-PR
CAIN T2,↑D2 ; SF-PR-1
MOVEI PSZ,↑D254
CAIE T2,↑D5 ; SILL-PR
CAIN T2,↑D6 ; SF-PR-2
MOVEI PSZ,↑D254
CAIE T2,↑D9 ; BRAGG-PR
CAIN T2,↑D47 ; SAC-PR
MOVEI PSZ,↑D254
; End of Kludge
; This isn't true if bypassing
LOAD T1,TLH,(TCB) ; Foreigner's name for us
IFN MNET,<CALL FNDNCT ; Put address of interface in T2
CAIA ; Not found
SKIPG T1,NTPSIZ(P1)> ; Get max size for that (interface) net
IFE MNET,<NETNUM T2,T1 ; Our net number ;CWL
SKIPG T1,INTSIZ(T2)> ; End of IFE MNET
MOVE T1,INTXPB ; None or 0, use maximum packet length
CAMLE PSZ,T1 ; Use it if smaller
MOVE PSZ,T1
TCPMX6:
CAMLE PSZ,TCPBYS ; User want bigger than we support?
MOVE PSZ,TCPBYS ; Yes, Clamp to our max
CAIGE PSZ,<.RTJST(-1,PIDO)+.RTJST(-1,PTDO)>*4+↑D8 ; Beware too
MOVX PSZ,<<.RTJST(-1,PIDO)+.RTJST(-1,PTDO)>*4+↑D8> ; small
STOR PSZ,TSMXP,(TCB) ; Set max packet size for connection
RESTORE
RET
; TCPIPK(Min size (w), Max siz (w) or 0, Adr of addresses or 0 if TCB)
; Get space for packet and fill in headers
; T1/ 0 (or maximum) data length, in octets
; T2/ Address of address block, or 0 if addresses in TCB are valid
; Address block: 32-bit Destination address
; 32-bit Source (local) address
; 16-bit Destination port
; 16-bit Source port
; TCB/ Contains addresses if T2 is zero; may be zero
; Call TCPIPK
;Ret+1: Cannot get space for packet, or neither T2 nor TCB specified
;Ret+2: Success, PKT & TPKT set, packet headers & options set
; PICKS/ contains maximum PIPL allowed
; PIPL/ header+option length
; T1/ PICKS-PIPL is available for data
TCPIPK::LOCAL <SIZW,ADRS>
MOVEM T2,ADRS ; Save Adr block address or 0
ADD T2,TCB ; Make sure have TCB or Adr argument
SKIPN T2 ; Both T2 & TCB zero is error
JRST TCPIPV ; Lose
; Try to assign a block of free storage for the packet to be sent.
MOVEI T2,TCPNPW ; Minimal packet (w/ max headers)
EXCH T2,T1
JUMPN T2,TCPIPB ; Use GETBBK for data
MOVEM T1,SIZW ; Save minimal size
CALL GETBLK ; Get block that big
JUMPE T1,TCPIPV ; Lose
JRST TCPIPC
TCPIPB: ADDI T2,3 ; Round up data count
ASH T2,-2 ; words
ADD T2,T1
CAMLE T2,INTXPW ; Don't ask for more than
MOVE T2,INTXPW ; Maximal pkt
CALL GETBBK ; Get biggest block of free storage
HLRZ SIZW,T1 ; Size, wds, of block gotten, if any
HRRZS T1 ; Clear garbage from addr pointer
JUMPE T1,TCPIPV ; Lose
SETSEC T1,INTSEC ; Make extended address (GETBBK)
TCPIPC: MOVE PKT,T1 ; Put in standard place
MOVEI T1,PKTELI+<<MINIHS+3>/4>-1 ; Clear through IP header
XMOVEI T2,(PKT) ; Source
XMOVEI T3,1(T2) ; Destination
SETZM 0(T2) ; Clear a word.
CALL XBLTA ; Clear the rest
; Fill in IP header
MOVEI T1,.INTVR
STOR T1,PIVER,(PKT) ; Store protocol version number
MOVEI T1,<MINIHS+3>/4 ; # words in smallest IN hdr
STOR T1,PIDO,(PKT) ; Set as initial data offset
ASH T1,2 ; Length, bytes
STOR T1,PIPL,(PKT) ; Current length
AOS T2,TCPSID ; Get the next segment ID
STOR T2,PISID,(PKT) ; Into packet
SETO T3, ; Max time to live
JUMPE TCB,TCPIPE ; No TCB values, use 0
LOAD T3,TTOS,(TCB) ; Copy Type of Service
STOR T3,PITOS,(PKT)
LOAD T3,TIFDF,(TCB) ; Copy Don't Fragment flag
STOR T3,PIDF,(PKT)
LOAD T3,TTTL,(TCB) ; Copy Time to Live
TCPIPE: STOR T3,PITTL,(PKT) ; Set Time to Live
MOVEI T3,.TCPFM ; TCP format
STOR T3,PIPRO,(PKT) ; Set into protocol field
; Stuff in all pertinent Internet options so we can know where
; the TCP portion will begin
CALL TCPIIO ; Insert IP Options & adjust PIDO
; and PIPL (Note TCB may be 0)
; Set pointer to TCP portion of packet now that all internet
; options have been set or reserved.
XMOVEI TPKT,PKTELI(PKT) ; Pointer to Internet portion
LOAD T2,PIDO,(PKT) ; Internet data offset (inc opt)
ADDB T2,TPKT ; T2 & TPKT now point at TCP area of pkt
MOVEI T1,<<MINTHS+3>/4>-1 ; Clear it
XMOVEI T3,1(T2) ; Destination
SETZM 0(T2) ; Clear a word.
CALL XBLTA ; Clear the rest
; Fill in IP addresses & TCP header
SKIPN ADRS ; Address block specified?
JRST TCPIPH ; No, use TCB
DMOVE T1,(ADRS) ; Get addresses from arg block
DMOVE T3,2(ADRS)
JRST TCPIPI
TCPIPH: LOAD T1,TFH,(TCB) ; Destination address
LOAD T2,TLH,(TCB) ; Source address
LOAD T3,TFP,(TCB) ; Destination port
LOAD T4,TLP,(TCB) ; Source port
TCPIPI:
STOR T1,PIDH,(PKT) ; Store the destination host
STOR T2,PISH,(PKT) ; Store the source host
STOR T3,PDP,(TPKT) ; Store the destination port
STOR T4,PSP,(TPKT) ; Store the source port
MOVEI T1,<<MINTHS+3>/4> ; Minimum TCP header size
STOR T1,PTDO,(TPKT) ; Set into TCP data offset field
ASH T1,2 ; Bytes in TCP header
LOAD T2,PIPL,(PKT) ; Current IP header length (inc opt)
ADD T2,T1 ; Total IP+TCP header length
STOR T2,PIPL,(PKT) ; Set Internet packet length
; Now the Internet header is initialized and we can add TCP options.
CALL TCPITO ; Insert TCP options & update PTDO
; and PIPL (Note TCB may be 0)
IFL <WID(PICKS)-WID(PIPL)>,<? PRINTX Width of PIPL exceeds that of PICKS>
MOVEI T1,-PKTELI(SIZW) ; Words for IP+TCP+DATA
ASH T1,2 ; Max # bytes (max PIPL)
MOVE T2,INTXPB ; Maximum for all interfaces
CAMLE T1,T2 ; Bigger than max allowed?
MOVE T1,T2 ; Yes, limit it
SKIPE TCB ; Have TCB?
LOAD T2,TSMXP,(TCB) ; Connection maximum
CAMLE T1,T2 ; Bigger than connection max?
MOVE T1,T2 ; Yes, limit it
STOR T1,PICKS,(PKT) ; Save max PIPL (PICKS unused til end)
LOAD T2,PIPL,(PKT) ; Total header size
SUB T1,T2 ; Octets available for data
MOVE T2,TODCLK ; Current millisecond number
STOR T2,PTS,(PKT) ; Store as timestamp
TDZA T2,T2 ; 0 OK
TCPIPV: SETO T2, ; NZ is bad
RESTORE
SKIPN T2 ; Skip if bad
AOS (P) ; Skip if good
RET
T